/**
 * 音频支持包头文件
 * Copyright (c) 2021 深圳市智辰科技有限公司
 * All rights reserved.
 */

#ifndef _AUDIO_H_
#define _AUDIO_H_

#include "stdc.h"
#include "std_type.h"
#include "nonos.h"
#include "share/wave_codec.h"
#include "share/notes_music.h"

#ifdef __cplusplus
extern "C" {
#endif


// Reg[0]:
// 7	EN_DEC		R	R/W  1’b0 The clock enable or data valid signal. When “1”, the decimation filter is enabled 
// 6	EN_INT		R	R/W  1’b0 The enable signal for the interpolating filter and sigma-delta modulator. When “1”, the interpolate filter is enabled. 
// 5	DECRST		R	R/W  1’b1 nrst of dec data path 
// 4	INTRST		R	R/W  1’b1 nrst of int data path 
// 3	DITHER_EN	R	R/W  1’b0 Digital dsm dither enable; 1=enable 
// 2	SCRAMBLE_EN	R	R/W  1’b1 Digital dsm out DEM module enable; 1=enable 
// 1	DSM_MODE	R	R/W  1’b0 Digital dsm module; 1=1+z^(-3), 0=1+z^(-1) 
// 0	HPF_EN		R	R/W  1’b1 Digital ADC highass filter enable; 1= enable 

// Reg[9]:
// 7  BCLKINV  R  R/W  1’b0 0 = BCLK not inverted; 1 = BCLK inverted 
// 6  RSV  -  -  1’b0  Reserved 
// 5  LRSWAP  R  R/W  1’b1 1 = swap left and right DAC data in audio interface; 0 = output left and right data as normal 
// 4  LRP  R  R/W  1’b0 Right, Left and I2S modes – LRCLK: 1 = invert LRCLK polarity; 0 = normal LRCLK polarity; DSP Mode – mode A/B select: 1 = MSB is available on 1st BCLK rising edge after LRC rising edge (mode B); 0 = MSB is available on 2nd BCLK rising edge after LRC rising edge (mode A) 
// 3:2  DCI_WL  R  R/W  2’b00 11 = 32 bits; 10 = 24 bits; 01 = 20 bits; 00 = 16 bits 
// 1:0  FMT[1:0]  R  R/W  2’b10 11 = DSP Mode; 10 = I2S Format; 01 = Left justified; 00 = Right justified

// 音频工作模式
typedef enum {	
	AUDIO_MODE_NONE = 0, 	// 停止工作	
	AUDIO_MODE_LOOPBACK, 	// 环回自激	
	AUDIO_MODE_PLAY_WAVE,   // 播放 wave
	AUDIO_MODE_PLAY_NOTES,  // 播放合成音乐
	AUDIO_MODE_RECORD,   	// 录音
	AUDIO_MODE_MAX,
} audio_mode_t;

// 音频采样速率
typedef enum {
	AUDIO_SAMPLE_RATE_8000  = 8000 ,
	AUDIO_SAMPLE_RATE_12000 = 12000,
	AUDIO_SAMPLE_RATE_16000 = 16000,
	AUDIO_SAMPLE_RATE_24000 = 24000,
	AUDIO_SAMPLE_RATE_48000 = 48000,
	AUDIO_SAMPLE_RATE_8021  = 8021 ,
	AUDIO_SAMPLE_RATE_11026 = 11026,
	AUDIO_SAMPLE_RATE_22059 = 22059,
	AUDIO_SAMPLE_RATE_44100 = 44100,
} audio_sample_rate_t;

// 最大采样值
#define MAX_SAMPLE_VALUE 			32767
// 合成 notes 音乐时，使用的采样速率
#define AUDIO_NOTES_SAMPLE_RATE		AUDIO_SAMPLE_RATE_8000
// 环回自激时，使用的采样速率
#define AUDIO_LOOPBACK_SAMPLE_RATE	AUDIO_SAMPLE_RATE_8000
// 录音时，使用的采样速率
#define AUDIO_RECORD_SAMPLE_RATE	AUDIO_SAMPLE_RATE_8000

#pragma pack(push, 1)

// 音频编解码器的寄存器
typedef struct {
	uint8_t addr;
	uint8_t value;
} audio_reg_t;

#pragma pack(pop)

// 寄存器写
void audio_write(uint8_t addr, uint8_t data);
// 寄存器读
uint8_t audio_read(uint8_t addr);
// 打印输出所有寄存器配置
void audio_dump_regs(void);
void audio_hw_set_freq(audio_sample_rate_t rate);
void audio_enable_adc(void);
void audio_disable_adc(void);
void audio_enable_dac(void);
void audio_disable_dac(void);
void audio_set_vol(uint8_t value);

/// 获取当前音频工作模式
audio_mode_t audio_mode(void);

/// 音频配置
/// @param volume 播放音量(1~100%)
void audio_config(const audio_reg_t *regs, audio_sample_rate_t rate, bool enableIrq, bool enableMic, bool enableSpeaker, uint8_t volume);

/// 音频功放打开与关闭函数原型
typedef std_err_t (*FUNC_PA_Switch)(uint8_t on);
/// 音频初始化
void audio_init(FUNC_PA_Switch funcPASwitch);
/// 设置音频功放打开与关闭函数
void audio_set_pa_switch(FUNC_PA_Switch funcPASwitch);

/// 音频停止
void audio_stop(void);

/// 录音采样数据块处理回调函数原型
/// @param samples 采集到的录音数据缓冲区
/// @param sampleCount 采集到的录音数据采样点数量
/// @return 是否需要继续录音: true 继续；false 停止
typedef bool (*FUNC_record_block_handler)(s16 *samples, uint16_t sampleCount);

/// 开始录音
/// 如果是直接开始录音，则录音回调函数返回 false 之后，就自动停止录音；
/// 如果是触发开始录音，则录音回调函数返回 false 之后，需重新触发后，再次自动录音；如果需要彻底停止触发录音，需要调用 audio_stop() 来停止。
/// @param handler 录音采样数据块处理回调函数
/// @param blockSize 每采样多少个点，就调用一次回调函数
/// @param trigLevel 用于触发录音的电平(=0 表示不用触发，直接开始录音)
/// @param trigCountMax 多少个采样点触发录音(=0 表示不用触发，直接开始录音)
std_err_t audio_record_start(FUNC_record_block_handler handler, uint16_t blockSize, uint16_t trigLevel, uint16_t trigCountMax);

/// 阻塞式采样一段时间的最大值
/// @param skipTimeMs 要跳过的头部噪声时间
/// @param totalTimeMs 总采样持续时间
/// @return 采样最大值
uint32_t audio_record_sync_detect_max(uint32_t skipTimeMs, uint32_t totalTimeMs);

/// 阻塞式采样一段时间的平均值
/// @param skipTimeMs 要跳过的头部噪声时间
/// @param totalTimeMs 总采样持续时间
/// @return 采样平均值
uint32_t audio_record_sync_detect_avg(uint32_t skipTimeMs, uint32_t totalTimeMs);

/// 开始环回
std_err_t audio_loopback_start(void);

/// 播放 wave 文件
/// @param data 要播放的 wave 数据指针
/// @param len 要播放的 wave 数据长度
/// @param volume 播放音量(1~100%)
/// @param repeat 重复次数
/// @param completeHandler 播放完成回调
std_err_t audio_play_wave(const void *data, uint32_t len, uint8_t volume, uint8_t repeat, FUNC_play_wave_complete completeHandler);

/// 音节音乐播放时状态数据结构
typedef struct st_notes_play_runtime_t {
	// 当前播放的音节
	const Note *note;
	// 播放音量(1~100%)
	uint8_t volume;
	// 播放速度(倍速，单位0.1倍)
	uint8_t speedX;
	// 音高(倍频，单位0.1倍)
	uint8_t toneX;
	// 重复次数
	uint8_t repeat;
	// 当前音节总共有多少个采样点
	int sampleCountTotal;
	// 当前音节半个频率周期内有多少个采样点
	int sampleCountHalfCycle;
	// 当前音节已经播放了多少个采样点
	int sampleCountPlayed;
	// 解码任务ID
	OSTaskId decodeTaskId;
	// 播放完成时回调函数
	void (*playCompleteCallback)(struct st_notes_play_runtime_t *notes);
} notes_play_runtime_t;

// notes 播放完成时回调函数原型
typedef void (*FUNC_play_notes_complete)(notes_play_runtime_t *notes);

/// 播放音节音乐
/// @param notes 要播放的章节音乐指针
/// @param sampleRate 播放时的采样速率
/// @param volume 播放音量(1~100%)，实际情况下音量超过16%，就可能失真！
/// @param speedX 播放速度(倍速，单位0.1倍)
/// @param toneX 音高(倍频，单位0.1倍)
/// @param repeat 重复次数
/// @param completeHandler 播放完成时回调函数
std_err_t audio_play_notes(const Note *notes, audio_sample_rate_t sampleRate, uint8_t volume, uint8_t speedX, uint8_t toneX, uint8_t repeat, FUNC_play_notes_complete completeHandler);

// FIXBUG: !!! 注意：当音频播放完成时，启动800ms的录音（跳过噪声），以便下次录音启动时避开噪声，快速采集到有效的数据 !!!
void audio_clear_record_noise(void);


#ifdef __cplusplus
}
#endif

#endif // _AUDIO_H_
